package com.loe.ui.page

import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.LinearLayout
import com.google.android.flexbox.FlexboxLayout
import com.loe.mvp.ext_java.safe
import com.loe.mvp.ext_view.visible
import com.loe.ui.*
import com.loe.ui.api.IUiView
import com.loe.ui.api.IUiViewGroup
import com.loe.ui.api.PageApi
import com.loe.ui.view.*
import com.loe.ui.view_other.*
import com.quickjs.JSArray
import com.quickjs.JSObject
import kotlinx.android.synthetic.main.activity_ui.*
import kotlin.reflect.KClass

class UiPage : FrameLayout, IUiViewGroup
{
    companion object
    {
        val classMap = hashMapOf<String, KClass<out IUiView>>(
            "ViewUI" to UiView::class,
            "TextUI" to UiTextView::class,
            "EditUI" to UiEditText::class,
            "ButtonUI" to UiButton::class,
            "ImageUI" to UiImageView::class,
            "ListUI" to UiListView::class,
            "GridUI" to UiListView::class,
            "FallUI" to UiListView::class,
            "ScrollUI" to UiScrollView::class,
            "FrameUI" to UiFrameLayout::class,
            "RowUI" to UiLinearLayout::class,
            "ColUI" to UiLinearLayout::class,
            "ViewPagerUI" to UiViewPager::class,

            "SlideUI" to UiSlideLayout::class,
            "CheckUI" to UiCheckText::class,
            "BannerUI" to UiBannerView::class,
            "FlexUI" to UiFlexLayout::class,
            "TabUI" to UiTabView::class,
        )
    }

    val idMap = HashMap<String, Int>()

    private var idCount = 100

    private var jsClass = ""

    var hasUI = false
        private set

    override var onSelect: (() -> Unit)? = null

    /** 注册id名称 */
    private fun registerIdName(view: View, idName: String)
    {
        if (idName.isNotEmpty())
        {
            view.id = idCount++
            idMap[idName] = view.id
        }
    }

    /** 清理UI模板 */
    fun removeAllChild()
    {
        idCount = 100
        idMap.clear()
        removeAllViews()
        hasUI = false
    }

    /**
     * 设置UI模板
     */
    override fun setUI(ui: JSObject, uiPage: UiPage?): View
    {
        removeAllChild()

        hasUI = true

        if (ui is JSArray)
        {
            // 递归子元素
            ui.forEach<JSObject>
            {
                createUI(it, this)
            }
            return this
        }
        return createUI(ui, this)
    }

    /** 创建UI */
    fun createUI(ui: JSObject, parent: ViewGroup? = null): View
    {
        var lParams: ViewGroup.LayoutParams? = null
        if (parent != null)
        {
            val width = ui.getDistance("width", ViewGroup.LayoutParams.WRAP_CONTENT)
            val height = ui.getDistance("height", ViewGroup.LayoutParams.WRAP_CONTENT)
            val gravity = ui.getGravity("layoutGravity")
            val margin = ui.getMargin()

            // 布局参数
            when (parent)
            {
                is FrameLayout ->
                {
                    val params = FrameLayout.LayoutParams(width, height)
                    params.gravity = gravity
                    params.setMargins(margin[0], margin[1], margin[2], margin[3])
                    lParams = params
                }
                is LinearLayout ->
                {
                    val params = LinearLayout.LayoutParams(width, height)
                    params.gravity = gravity
                    ui.gotHasDouble("weight") { params.weight = it.toFloat() }
                    params.setMargins(margin[0], margin[1], margin[2], margin[3])
                    lParams = params
                }
                is UiSlideLayout ->
                {
                    val params = MarginLayoutParams(width, height)
                    params.setMargins(margin[0], margin[1], margin[2], margin[3])
                    lParams = params
                }
                is UiFlexLayout ->
                {
                    val params = FlexboxLayout.LayoutParams(width, height)
                    params.setMargins(margin[0], margin[1], margin[2], margin[3])
                    parent.initChildParams(ui, params)
                    lParams = params
                }
                else ->
                {
                    val params = ViewGroup.LayoutParams(width, height)
                    lParams = params
                }
            }
        }

        val type = ui.gotString("type")
        val cls = classMap[type] ?: UiLinearLayout::class
        val view = cls.constructors.find { it.parameters.size == 1 }?.call(context)
        registerIdName(view as View, ui.gotString("id"))
        lateinit var addView: View
        view.apply()
        {
            // bg
            initBg(ui)
            // padding
            initPadding(ui)
            // transZ
            ui.gotHasString("transZ") { translationZ = it.pxFloat }
            // alpha
            ui.gotHasString("alpha") { alpha = it.pxFloat }
            // scale
            initScale(ui)
            // rotation
            ui.gotHasString("rotation") { rotation = it.pxFloat }
            // visible
            ui.gotHasBoolean("visible") { visible = it }
            // focus
            initFocus(ui)
            // onSelect
            initOnSelect(ui)
            // selector
            initSelector(ui)
            // corner
            initCorner(ui)
            // minWidth
            ui.gotHasString("minWidth") { minimumWidth = it.px }
            // minHeight
            ui.gotHasString("minHeight") { minimumHeight = it.px }
            // onClick
            initOnClick(ui)
            // delayClick
            initDelayClick(ui)
            // link
            initLink(ui)

            addView = setUI(ui, this@UiPage)

            // 执行js
            ui.gotHasFunction("onCreate")
            { callback ->
                callback.call(view.jsObject, null)
            }
        }

        parent?.addView(addView, lParams)
        return addView
    }

    override var uiPage: UiPage? = this

    /** 运行js方法 */
    fun runJsFun(name: String, vararg params: Any): Any?
    {
        return jsObject.executeFunction2(name, *params)
    }

    override fun onWindowVisibilityChanged(visibility: Int)
    {
        if (jsClass.isNotEmpty()) safe()
        {
            when (visibility)
            {
                VISIBLE -> jsObject.executeFunction2("onShow")
                GONE -> jsObject.executeFunction2("onHide")
            }
        }

        super.onWindowVisibilityChanged(visibility)
    }

    /****************************************** 初始化 ****************************************/

    constructor(context: Context) : super(context)
    {
        init(context)
    }

    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
    {
        init(context)
    }

    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
    {
        init(context)
    }

    private fun init(context: Context)
    {
    }

    /** 初始化页面 */
    fun init(jsClass: String, onCreate: ((jsObject: JSObject) -> Unit)? = null)
    {
        safe()
        {
            this.jsClass = jsClass
            jo = null
            onCreate?.invoke(jsObject)
            jsObject.executeFunction2("onCreate")
        }
    }

    private var jo: JSObject? = null

    override val jsObject: JSObject
        get()
        {
            if (jo != null) return jo!!

            jo = if (jsClass.isEmpty())
            {
                JSObject(jsContext)
            } else
            {
                try
                {
                    jsContext.executeObjectScript("new $jsClass()", null)
                } catch (e: Exception)
                {
                    jsContext.executeObjectScript("new $jsClass()", null)
                }
            }
            return jo!!.also { PageApi(this, it) }
        }
}